package se.webbzon.oschi01.gui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

public class SortedListModel<T> implements ListModel<T>, Set<T> {
	
	private final Collection<ListDataListener> listeners;
	
	private final SortedSet<T> sortedSet; 
	
	public SortedListModel(Comparator<T> cmp) {
		sortedSet = new TreeSet<T>(cmp);
		listeners = new ArrayList<ListDataListener>();
	}
	
	public SortedListModel(Collection<T> c) {
		sortedSet = new TreeSet<T>(c);
		listeners = new ArrayList<ListDataListener>();
	}
	
	public SortedListModel(ListModel<T> model, Comparator<T> cmp) {
		this(cmp);
		for (int i = 0; i < model.getSize(); i++) {
			sortedSet.add(model.getElementAt(i));
		}
	}
	
	public SortedListModel(Collection<T> c, Comparator<T> cmp) {
		this(cmp);
		sortedSet.addAll(c);
	}

	@Override public void addListDataListener(ListDataListener l) {
		listeners.add(l);
	}

	@Override public synchronized T getElementAt(int index) {
		int i = 0;
		for (T t : sortedSet) {
			if (i == index)
				return t;
			else
				i++;
		}
		throw new IndexOutOfBoundsException();
	}

	@Override public synchronized int getSize() {
		return sortedSet.size();
	}

	@Override public void removeListDataListener(ListDataListener l) {
		listeners.remove(l);
	}

	@Override public synchronized boolean add(T e) {
		if (sortedSet.add(e)) {
			ListDataEvent ev = new ListDataEvent(this,ListDataEvent.INTERVAL_ADDED,0,sortedSet.size()-1);
			for (ListDataListener listener : listeners.toArray(new ListDataListener[0]))
				listener.contentsChanged(ev);
			return true;
		} else
			return false;
	}

	@Override public synchronized boolean addAll(Collection<? extends T> c) {
		if (sortedSet.addAll(c)) {
			ListDataEvent ev = new ListDataEvent(this,ListDataEvent.INTERVAL_ADDED,0,sortedSet.size()-1);
			for (ListDataListener listener : listeners.toArray(new ListDataListener[0]))
				listener.contentsChanged(ev);
			return true;
		} else
			return false;
	}

	@Override public synchronized void clear() {
		sortedSet.clear();
		ListDataEvent ev = new ListDataEvent(this,ListDataEvent.INTERVAL_REMOVED,0,sortedSet.size()-1);
		for (ListDataListener listener : listeners.toArray(new ListDataListener[0]))
			listener.contentsChanged(ev);
	}

	@Override public synchronized boolean contains(Object o) {
		return sortedSet.contains(o);
	}

	@Override public synchronized boolean containsAll(Collection<?> c) {
		return sortedSet.containsAll(c);
	}

	@Override public synchronized boolean isEmpty() {
		return sortedSet.isEmpty();
	}

	@Override public synchronized Iterator<T> iterator() {
		return sortedSet.iterator();
	}

	@Override public synchronized boolean remove(Object o) {
		if (sortedSet.remove(o)) {
			ListDataEvent ev = new ListDataEvent(this,ListDataEvent.INTERVAL_REMOVED,0,sortedSet.size()-1);
			for (ListDataListener listener : listeners.toArray(new ListDataListener[0]))
				listener.contentsChanged(ev);
			return true;
		} else
			return false;
	}

	@Override public synchronized boolean removeAll(Collection<?> c) {
		if (sortedSet.removeAll(c)) {
			ListDataEvent ev = new ListDataEvent(this,ListDataEvent.INTERVAL_REMOVED,0,sortedSet.size()-1);
			for (ListDataListener listener : listeners.toArray(new ListDataListener[0]))
				listener.contentsChanged(ev);
			return true;
		} else 
			return false;
	}

	@Override public synchronized boolean retainAll(Collection<?> c) {
		if (sortedSet.retainAll(c)) {
			ListDataEvent ev = new ListDataEvent(this,ListDataEvent.INTERVAL_REMOVED,0,sortedSet.size()-1);
			for (ListDataListener listener : listeners.toArray(new ListDataListener[0]))
				listener.contentsChanged(ev);
			return true;
		} else
			return false;
	}

	@Override public synchronized int size() {
		return getSize();
	}

	@Override public synchronized Object[] toArray() {
	return sortedSet.toArray();
	}

	@Override public synchronized <V> V[] toArray(V[] a) {
		return sortedSet.toArray(a);
	}

}
